import os
import sys
import threading
from http.server import SimpleHTTPRequestHandler, HTTPServer
import urllib.parse
from datetime import datetime
import mimetypes
from functools import lru_cache
from concurrent.futures import ThreadPoolExecutor
import signal

class CustomHandler(SimpleHTTPRequestHandler):
    def __init__(self, *args, **kwargs):
        self.executor = ThreadPoolExecutor(max_workers=10)
        super().__init__(*args, **kwargs)

    @lru_cache(maxsize=100)
    def get_file_info(self, full_path):
        try:
            file_type, _ = mimetypes.guess_type(full_path)
            if file_type is None:
                file_type = "application/octet-stream"
            
            mtime = os.path.getmtime(full_path)
            ctime = os.path.getctime(full_path)
            size = os.path.getsize(full_path)
            
            modified_date = datetime.fromtimestamp(mtime).strftime('%Y-%m-%d %H:%M:%S')
            created_date = datetime.fromtimestamp(ctime).strftime('%Y-%m-%d %H:%M:%S')
            file_size = size  # 保留原始大小用于排序
            
            return file_type, modified_date, created_date, file_size, mtime, ctime
        except Exception as e:
            print(f"Error processing file {full_path}: {e}")
            return None, None, None, None, None, None

    def list_directory(self, path):
        try:
            entries = os.listdir(path)
        except OSError:
            self.send_error(404, "No permission to list directory")
            return None

        displaypath = urllib.parse.unquote(self.path)
        query = urllib.parse.parse_qs(urllib.parse.urlparse(self.path).query)
        sort_by = query.get('sort', ['name'])[0]
        reverse = query.get('order', ['asc'])[0] == 'desc'

        html = f"""
        <html>
        <head>
            <meta charset="UTF-8">
            <title>目录列表: {displaypath}</title>
            <style>
                body {{ font-family: Arial, sans-serif; }}
                table {{ border-collapse: collapse; width: 100%; }}
                th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
                th {{ background-color: #f2f2f2; cursor: pointer; }}
            </style>
            <script>
                function sortTable(column) {{
                    var url = new URL(window.location);
                    url.searchParams.set('sort', column);
                    if (url.searchParams.get('order') === 'asc') {{
                        url.searchParams.set('order', 'desc');
                    }} else {{
                        url.searchParams.set('order', 'asc');
                    }}
                    window.location = url;
                }}
            </script>
        </head>
        <body>
            <h2>目录列表: {displaypath}</h2>
            <table>
                <tr>
                    <th onclick="sortTable('name')">文件名</th>
                    <th onclick="sortTable('mtime')">修改日期</th>
                    <th onclick="sortTable('ctime')">创建日期</th>
                    <th onclick="sortTable('size')">文件大小</th>
                    <th onclick="sortTable('type')">文件类型</th>
                </tr>
        """

        futures = []
        for entry in entries:
            full_path = os.path.join(path, entry)
            futures.append(self.executor.submit(self.get_file_info, full_path))

        file_list = []
        for entry, future in zip(entries, futures):
            full_path = os.path.join(path, entry)
            file_type, modified_date, created_date, file_size, mtime, ctime = future.result()
            if file_type is None:
                continue
            file_list.append((entry, full_path, file_type, modified_date, created_date, file_size, mtime, ctime))

        # 排序
        if sort_by == 'name':
            file_list.sort(key=lambda x: x[0].lower(), reverse=reverse)
        elif sort_by == 'mtime':
            file_list.sort(key=lambda x: x[6], reverse=reverse)
        elif sort_by == 'ctime':
            file_list.sort(key=lambda x: x[7], reverse=reverse)
        elif sort_by == 'size':
            file_list.sort(key=lambda x: x[5], reverse=reverse)
        elif sort_by == 'type':
            file_list.sort(key=lambda x: x[2], reverse=reverse)

        for entry, full_path, file_type, modified_date, created_date, file_size, _, _ in file_list:
            URL_path = urllib.parse.quote(self.path + entry)
            formatted_size = self.format_file_size(file_size)

            html += f"""
                <tr>
                    <td><a href="{URL_path}">{'📁 ' if os.path.isdir(full_path) else ''}{entry}</a></td>
                    <td>{modified_date}</td>
                    <td>{created_date}</td>
                    <td>{formatted_size}</td>
                    <td>{file_type}</td>
                </tr>
            """

        html += """
            </table>
        </body>
        </html>
        """
        
        self.send_response(200)
        self.send_header("Content-type", "text/html; charset=utf-8")
        self.end_headers()
        self.wfile.write(html.encode('utf-8'))

    def format_file_size(self, size):
        for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
            if size < 1024.0:
                return f"{size:.2f} {unit}"
            size /= 1024.0

def run_server(port):
    server_address = ('', port)
    httpd = HTTPServer(server_address, CustomHandler)
    
    print(f"HTTP服务器已启动，端口：{port}...")
    print("按 Ctrl+C 退出程序。")
    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        print("\n正在退出...")
        httpd.shutdown()

def find_available_port(start_port):
    port = start_port
    while True:
        try:
            server = HTTPServer(('', port), CustomHandler)
            server.socket.close()
            return port
        except OSError:
            port += 1

def signal_handler(signum, frame):
    print("\n正在退出...")
    sys.exit(0)

if __name__ == "__main__":
    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)

    start_port = 8000
    available_port = find_available_port(start_port)
    run_server(available_port)
